package biolabs.mcl

import biolabs.core.{Application, BioObject, Instantiable}
import biolabs.mcl.syntax._

object SuperTypeSpec {
	def analyze(ast: SuperTypeSpecAST, model: ModelDefinition, containments: List[Containment], app: Application): AnalysisResult[SuperTypeSpec] = {
		// analyze the type
		val superType = ActualType.analyze(ast.typeSpec, model, model.typeParameterMap, app) match {
			case AnalysisSuccess(t) => t
			case AnalysisError(msg) => return AnalysisError(msg)
		}

		// get the supertype's class
		val clazz = superType.rawType

		// check that super type with a time scale adjustment extends BioObject
		if(ast.timeScale.isDefined && !classOf[BioObject].isAssignableFrom(clazz))
				return AnalysisError("Time scaling used with " + clazz + " which does not extend " + classOf[BioObject])

		// analyze initialization arguments
		val initArgs = {
			val (suc, err) = ast.initArgs map { Expr.analyze(_, containments, model) } partition { _.successful }
			if(!err.isEmpty)
				return AnalysisError(err map {_.getErrorMessage()} mkString "\n")
			suc map { _.getResult() }
		}

		AnalysisSuccess(new SuperTypeSpec(superType, initArgs, ast.timeScale))
	}
}

class SuperTypeSpec(
	val superType: ActualType,
	val initArgs: List[Expr],
	val timeScale: Option[(String, String)]
) {
	lazy val extendsBioObject = superType.isDescendantOf(classOf[BioObject])
	lazy val isInstantiable = classOf[Instantiable[_]].isAssignableFrom(superType.rawType)
	def getMethod(name: String, parameterTypes: Array[SingleType]) = superType.getMethod(name, parameterTypes)
}